package api

import (
	"GopherFocus/app/model"
	"GopherFocus/app/shared"
	"GopherFocus/app/system/index/internal/define"
	"GopherFocus/app/system/index/internal/service"
	"GopherFocus/library/response"
	"github.com/gogf/gf/net/ghttp"
)

var User = userApi{}

type userApi struct{}

// 用户-首页
// 1.define模型包含一个id（路由中的命名参数），和ContentGetListInput结构体(用户获取Content数据在/user/:id的URL下展示该用户发布的文章，问答，主题等)
// 2.解析参数，将id作为UserID传入userApi的getContentList接口
// 3.在getContentList中define一个请求结构体，解析请求参数，将UserId和Type赋值给该结构体
// 4.通过User的GetList获取用户主页Content列表
// 5.User的GetList首先会根据Type和UserId参数获取Content列表，然后根据UserId获取用户信息，
// 		最后根据UserId进行Content的分类统计（用于前端展示用户发布的文章、问答、主题的数据）
// 6.通过View的GetTitle获取分级标题
// 7.最终返回的数据需要带有ContentType，作为前端展示时，用于构造不同分类和栏目所对应的URL（例如页面上的"Ta的文章"对应链接: /user/:id?type=article）
// ContentType就是用来构造/user/:id?type=article中的type=article部分的
func (a *userApi) Index(r *ghttp.Request) {
	var (
		req *define.UserGetListReq
	)
	if err := r.Parse(&req); err != nil {
		service.View.Render500(r, model.View{
			Error: err.Error(),
		})
	}
	a.getContentList(r, req.Type, req.Id)
}

// 获取用户主页内容接口
func (a *userApi) getContentList(r *ghttp.Request, contentType string, userId uint) {
	var (
		req *define.UserGetListReq
	)
	if err := r.Parse(&req); err != nil {
		service.View.Render500(r, model.View{
			Error: err.Error(),
		})
	}
	req.UserId = userId
	req.Type = contentType
	if data, err := service.User.GetList(r.Context(), req.UserGetListInput); err != nil {
		service.View.Render500(r, model.View{
			Error: err.Error(),
		})
	} else {
		title := service.View.GetTitle(r.Context(), &define.ViewGetTitleInput{
			ContentType: req.Type,
			CategoryId:  req.CategoryId,
		})
		service.View.Render(r, model.View{
			Title:       title,
			ContentType: req.Type,
			Data:        data,
		})
	}
}

// 获取用户个人信息（同时显示个人发布的文章/问答/主题/消息数量）
// 直接根据上下文对象获取用户ID，然后根据用户ID查询dao.User获取用户信息
func (a *userApi) Profile(r *ghttp.Request) {
	getProfile, err := service.User.GetProfile(r.Context())
	if err != nil {
		service.View.Render500(r, model.View{
			Error: err.Error(),
		})
	} else {
		title := "用户" + getProfile.Nickname + "的资料"
		// 为何这里KeyWords和Description也要设置为title
		service.View.Render(r, model.View{
			Title:       title,
			Keywords:    title,
			Description: title,
			Data:        getProfile,
		})
	}
}

// 更新个人资料
func (a *userApi) UpdateProfile(r *ghttp.Request) {
	var (
		req *define.UserUpdateProfileReq
	)
	if err := r.Parse(&req); err != nil {
		// 此处不需要返回Service.View.Renderxxx，因为该页面不需要返回Content列表
		// 如果更新失败直接退出
		response.JsonExit(r, 1, err.Error())
	}
	if err := service.User.UpdateProfile(r.Context(), req.UserUpdateProfileInput); err != nil {
		response.JsonExit(r, 1, err.Error())
	} else {
		response.JsonExit(r, 0, nil)
	}
}

// 更新个人头像
// 1.获取文件上传表单数据
// 2.调用Upload接口对上传文件进行处理
// 		2.1 FileUploadInput 包含上传的文件对象（*ghttp.UploadFile）和RandomName（表示是否使用随机生成的文件名）
// 		2.2 获取上传文件路径的配置
// 		2.3 对文件对象设置文件名 input.File.FileName = input.Name
//		2.4 如果一分钟内上传超过10次，则不允许再上传
//		2.5 获取当前日期，根据 上传路径配置、当前日期、是否使用随机生成的文件名 构造input.File.Save()的路径（第一个参数的保存路径，第二个参数是是否使用随机生成的文件名）
//		2.6 创建model.File实例，新插入一条File数据到数据库
//		2.7 返回上传的文件信息（文件名、文件路径、文件URl，用户ID）
// 3.根据上传文件url地址作为头像地址调用更新头像的接口
func (a *userApi) UpdateAvatar(r *ghttp.Request) {
	// file为前端提交的文件表单字段名
	// r.GetUploadFile返回*ghttp.UploadFile类型
	file := r.GetUploadFile("file")
	// 判断提交的文件是否为空，如果为空则返回报错提示
	if file == nil {
		response.JsonExit(r, 1, "请选择需要上传的文件")
	}
	uploadResult, err := service.File.Upload(r.Context(), define.FileUploadInput{
		File:       file,
		RandomName: true,
	})
	if err != nil {
		response.JsonExit(r, 1, err.Error())
	}

	var avatar string
	if uploadResult != nil {
		avatar = uploadResult.Url
	}
	input := define.UserUpdateAvatar{
		Avatar: avatar,
	}
	// 更新头像
	if err = service.User.UpdateAvatar(r.Context(), input); err != nil {
		response.JsonExit(r, 1, err.Error())
	} else {
		response.JsonExit(r, 0, "")
	}
}

// 修改密码页面
func (a *userApi) Password(r *ghttp.Request) {
	if getProfile, err := service.User.GetProfile(r.Context()); err != nil {
		service.View.Render500(r, model.View{
			Error: err.Error(),
		})
	} else {
		title := "用户 " + getProfile.Nickname + " 修改密码"
		service.View.Render(r, model.View{
			Title:       title,
			Keywords:    title,
			Description: title,
			Data:        getProfile,
		})
	}
}

// 更新密码
func (a *userApi) UpdatePassword(r *ghttp.Request) {
	var (
		req *define.UserPasswordReq
	)
	if err := r.Parse(&req); err != nil {
		response.JsonExit(r, 1, err.Error())
	}
	if err := service.User.UpdatePassword(r.Context(), req.UserPasswordInput); err != nil {
		response.JsonExit(r, 1, err.Error())
	} else {
		response.JsonExit(r, 0, "")
	}
}

// 我的文章页面
func (a *userApi) Article(r *ghttp.Request) {
	a.getContentList(r, model.ContentTypeArticle, shared.Context.Get(r.Context()).User.Id)
}

// 我的主题页面
func (a *userApi) Topic(r *ghttp.Request) {
	a.getContentList(r, model.ContentTypeTopic, shared.Context.Get(r.Context()).User.Id)
}

// 我的问答页面
func (a *userApi) Ask(r *ghttp.Request) {
	a.getContentList(r, model.ContentTypeAsk, shared.Context.Get(r.Context()).User.Id)
}

// 我的消息页面
func (a *userApi) Message(r *ghttp.Request) {
	var (
		req *define.UserGetMessageReq
	)
	if err := r.Parse(&req); err != nil {
		response.JsonExit(r, 1, err.Error())
	}
	if getListRes, err := service.User.GetMessageList(r.Context(), req.UserGetMessageInput); err != nil {
		// 这里需要渲染页面，所以用Render而不用JsonExit
		service.View.Render500(r, model.View{
			Error: err.Error(),
		})
	} else {
		// 为什么这里要这样返回？？?
		service.View.Render(r, model.View{
			ContentType: req.TargetType,
			Data:        getListRes,
		})
	}
}

// 注销登录
func (a *userApi) Logout(r *ghttp.Request) {
	if err := service.User.Logout(r.Context()); err != nil {
		service.View.Render500(r, model.View{
			Error: err.Error(),
		})
	} else {
		// 重定向到登录页面: /login
		r.Response.RedirectTo(service.Middleware.GetLoginUrl())
	}
}
